#if !defined(ximera_common_factory_hpp)
#define ximera_common_factory_hpp

// -----------------------------------------------------------

#include <ximera/types.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <ximera/exception.hpp>

#include <map>

namespace ximera
{
    XIMERA_DECLARE_EXCEPTION(UnregisteredTypeException, L"Type was not registered in the factory");

    template <typename Base, typename Id, typename Creator = Base* ()>
    class Factory
    {
    public:
        typedef Id IdType;
        typedef boost::function<Creator> CreatorType;
        typedef std::map<IdType, CreatorType> CreatorMap;
        typedef typename CreatorMap::iterator Iterator;
        typedef typename CreatorMap::const_iterator ConstIterator;

    public:
        template <typename T>
        static Base* defaultCreator() { return new T(); }

    public:
        UInt32 count() const;
        bool subscribe(IdType const& id, CreatorType const& creator);
        bool unsubscribe(IdType const& id);

        Iterator begin();
        ConstIterator begin() const;

        Iterator end();
        ConstIterator end() const;

        Base* create(IdType const& id) const;
        ConstIterator find(IdType const& id) const;

        template <typename DestType>
        DestType* create(IdType const& id) const;

    private:        
        CreatorMap _creators;
    };
}

#include <ximera/common/inline/factory.inl>

// -----------------------------------------------------------

#endif
